\chapter{QMetaObject 结构体}

QMetaObject 类包含了 Qt 对象的元信息。更多内容...。

\begin{tabular}{|r|l|}
	\hline
	属性 & 方法 \\
	\hline
	头文件 & \#include <QMetaObject>\\      
	\hline
	qmake & QT += core\\      
	\hline
\end{tabular}

\section{公共成员类型}


\begin{tabular}{|r|l|}   
\hline
类型	& 名称 \\ 
\hline
class	& Connection \\ 
\hline
\end{tabular}


\section{公共成员函数}

\begin{longtable}[l]{|r|m{28em}|}   
\hline
QMetaClassInfo	& classInfo(int \emph{index}) const \\ 
\hline
int &	classInfoCount() const \\
\hline
int	&classInfoOffset() const\\
\hline
const char *	&className() const\\
\hline
QMetaMethod	&constructor(int index) const\\
\hline
int	&constructorCount() const\\
\hline
QMetaEnum	&enumerator(int index) const\\
\hline
int	&enumeratorCount() const\\
\hline
int	&enumeratorOffset() const\\
\hline
int&	indexOfClassInfo(const char *name) const\\
\hline
int	&indexOfConstructor(const char *constructor) const\\
\hline
int	&indexOfEnumerator(const char *name) const\\
\hline
int	&indexOfMethod(const char *method) const\\
\hline
int	&indexOfProperty(const char *name) const\\
\hline
int	&indexOfSignal(const char *signal) const\\
\hline
int&	indexOfSlot(const char *slot) const\\
\hline
bool	&inherits(const QMetaObject *metaObject) const\\
\hline
QMetaMethod	&method(int index) const\\
\hline
int	&methodCount() const\\
\hline
int	&methodOffset() const\\
\hline
QObject *	&newInstance(QGenericArgument val0 = QGenericArgument(nullptr), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()) const\\
\hline
QMetaProperty	&property(int index) const\\
\hline
int&	propertyCount() const\\
\hline
int	&propertyOffset() const\\
\hline
const QMetaObject *	&superClass() const\\
\hline
QMetaProperty	&userProperty() const\\
\hline
\end{longtable}



\section{静态公共成员}

\begin{longtable}[l]{|l|m{28em}|}
\hline
返回类型 &	函数 \\ 
\hline
bool	&checkConnectArgs(const char *signal, const char *method) \\
\hline
bool	&checkConnectArgs(const QMetaMethod \&signal, const QMetaMethod \&method) \\
\hline
void	&connectSlotsByName(QObject *object) \\
\hline
bool	&invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument(nullptr), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument())\\
\hline
bool	&invokeMethod(QObject *obj, const char *member, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument(0), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument())\\
\hline
bool	&invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericArgument val0 = QGenericArgument(0), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument())\\
\hline
bool	&invokeMethod(QObject *obj, const char *member, QGenericArgument val0 = QGenericArgument(0), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument())\\
\hline
bool	&invokeMethod(QObject *context, Functor function, Qt::ConnectionType type = Qt::AutoConnection, FunctorReturnType *ret = nullptr) \\
\hline
bool	&invokeMethod(QObject *context, Functor function, FunctorReturnType *ret) \\
\hline
QByteArray&	normalizedSignature(const char *method) \\
\hline
QByteArray&	normalizedType(const char *type)\\
\hline
\end{longtable}

\section{宏定义}

\begin{tabular}{|l|l|}
\hline
返回类型	& 宏定义 \\
\hline
QGenericArgument	& Q\_ARG(Type, const Type \&value) \\
\hline
QGenericReturnArgument&	Q\_RETURN\_ARG(Type, Type \&value) \\
\hline
\end{tabular}



\section{详细描述}

Qt 的元对象系统负责信号槽跨对象通信机制、运行时类型信息和 Qt 的属性系统。
应用中的每个 QObject 子类都有一个唯一的 QMetaObject 实例（译者注：与类一一对应，即同一个 QObject 子类的任意对象，都使用同一个 QMetaObject），其中保存了这个 QObject 子类的所有元信息，可以通过 QObject::metaObject() 获取。

QMetaObject 在应用编写中通常不需要，但在进行元编程时会非常有用，例如脚本引擎或者用户界面生成器。

最常用的成员函数有：

\begin{compactitem}
\item className() 返回类的名称。
\item superClass() 返回父类对应的元对象。
\item method() 和 methodCount() 提供关于一个类的元方法（信号、槽和其它可动态调用的成员方法）。
\item enumerator() 和 enumeratorCount() 提供一个类的枚举类型的信息。
\item propertyCount() 和 property() 提供一个类的属性的信息。
\item constructor() 和 constructorCount() 提供一个类的元构造函数的信息。
\end{compactitem}


索引函数 indexOfConstructor()、indexOfMethod()、indexOfEnumerator() 和 indexOfProperty() 将构造函数、成员函数、枚举类型和属性的名称映射为索引。例如，当连接信号槽时，Qt 内部使用 indexOfMethod() 进行检索。

类可以拥有一系列 名称—数值 格式的附加信息，保存在 QMetaClassInfo 对象中。信息条目数量可通过 classInfoCount()查询， classInfo()返回单条信息，也可通过 indexOfClassInfo() 检索信息条目。

\begin{notice}
元对象系统的操作通常是线程安全的，比如元对象是在编译期生成的静态只读实例。
然而，如果元对象在被程序动态修改了（如通过 QQmlPropertyMap），应用需要显示地同步对相关对象的访问。
\end{notice}

\begin{seeAlso}
QMetaClassInfo、QMetaEnum、QMetaMethod、QMetaProperty、QMetaType 和 Meta-Object System。
\end{seeAlso}

\section{成员函数文档}

[static] bool QMetaObject::checkConnectArgs(const char \emph{*signal}, const char \emph{*method})

如果 signal 和 method 的参数能够匹配则返回 true，否则返回 false。

signal 和 method 都被假设是已经规范化的。

\begin{seeAlso}
normalizedSignature()。
\end{seeAlso}

[static] bool QMetaObject::checkConnectArgs(const QMetaMethod \emph{\&signal}, const QMetaMethod \emph{\&method})

这是一个重载函数。

如果 signal 和 method 的参数能够匹配则返回 true，否则返回 false。

本函数在 Qt 5.0 中被引入。

QMetaClassInfo QMetaObject::classInfo(int \emph{index}) const

返回对应 index 的类型信息的元数据对象。

范例：

\begin{cppcode}
class MyClass : public QObject
 {
     Q_OBJECT
     Q_CLASSINFO("author", "Sabrina Schweinsteiger")
     Q_CLASSINFO("url", "http://doc.moosesoft.co.uk/1.0/")

 public:
     ...
 };
\end{cppcode}


%%%%%%%%%%%%%%%%

\begin{seeAlso}
classInfoCount()、classInfoOffset() 和 indexOfClassInfo()。
\end{seeAlso}

int QMetaObject::classInfoCount() const

返回该类信息条目数量。

\begin{seeAlso}
classInfo()、classInfoOffset() 和 indexOfClassInfo()。
\end{seeAlso}

int QMetaObject::classInfoOffset() const

返回类信息在该类中的偏移量，即第一条类信息的编号。

若该类没有包含类信息的父类，则偏移量为 0，否则偏移量是所有父类的类信息数量的总和。

\begin{seeAlso}
classInfo()、classInfoCount() 和 indexOfClassInfo()。
\end{seeAlso}

const char *QMetaObject::className() const

返回该类的名称。

\begin{seeAlso}
superClass()。
\end{seeAlso}

[static] void QMetaObject::connectSlotsByName(QObject \emph{*object})

递归检索 \emph{object} 和所有子对象，将它们的信号连接至 object 中匹配的槽，匹配格式如下：

\begin{lstlisting}
void on_<对象名>_<信号名>(<信号参数>);
\end{lstlisting}

假设有一个对象名 为 button1 的 QPushButton 类型的子对象，则捕获它的 clicked() 信号的槽应为：

\begin{cppcode}
void on_button1_clicked();
\end{cppcode}

若 object 对象自身的名字已设置，则它自己的信号也会被连接至对应的槽。

\begin{seeAlso}
QObject::setObjectName().
\end{seeAlso}

%%%%%%%%%%%
QMetaMethod QMetaObject::constructor(int \emph{index}) const

返回指定 \emph{index} 的构造函数的元数据。

该函数在 Qt 4.5 中被引入。

\begin{seeAlso}
constructorCount() 和 newInstance()。
\end{seeAlso}

int QMetaObject::constructorCount() const

返回此类的构造函数个数。

该函数在 Qt 4.5 中被引入。

\begin{seeAlso}
constructor() 和 indexOfConstructor()。
\end{seeAlso}

QMetaEnum QMetaObject::enumerator(int \emph{index}) const

返回指定 \emph{index} 的枚举类型的元数据。

\begin{seeAlso}
enumeratorCount()、enumeratorOffset() 和 indexOfEnumerator()。
\end{seeAlso}

int QMetaObject::enumeratorCount() const

返回该类的枚举类型的个数。

\begin{seeAlso}
enumerator()、enumeratorOffset() 和 indexOfEnumerator()。
\end{seeAlso}
	
int QMetaObject::enumeratorOffset() const

返回该类的枚举类型偏移量，即首个枚举变量的编号。

若该类没有包含枚举类型的父类，则偏移量为 0，否则偏移量是所有父类的枚举类型数量的总和。

\begin{seeAlso}
enumerator()、enumeratorCount() 和 indexOfEnumerator()。
\end{seeAlso}

int QMetaObject::indexOfClassInfo(const char \emph{*name}) const

查找名为 \emph{name} 的类型信息条目并返回其编号，未找到则返回-1。

\begin{seeAlso}
classInfo()、classInfoCount() 和 classInfoOffset()。
\end{seeAlso}

int QMetaObject::indexOfConstructor(const char \emph{*constructor}) const

查找名为 \emph{constructor} 的构造函数并返回其编号，未找到则返回-1。

\begin{notice}
constructor 需要为规范化的格式，如 normalizedSignature() 的返回值。
\end{notice}

该函数在 Qt 4.5 中被引入。

\begin{seeAlso}
constructor()、constructorCount() 和 normalizedSignature()。
\end{seeAlso}

int QMetaObject::indexOfEnumerator(const char \emph{*name}) const

查找名为 \emph{name} 的枚举类型并返回其编号，未找到则返回-1。

\begin{notice}
enumerator(), enumeratorCount() 和 enumeratorOffset().
\end{notice}

int QMetaObject::indexOfMethod(const char \emph{*method}) const

查找名为 \emph{method} 的方法并返回其编号，未找到则返回-1。

\begin{notice}
method 需要为规范化的格式，如 normalizedSignature() 的返回值。
\end{notice}

\begin{seeAlso}
method()、methodCount()、methodOffset() 和 normalizedSignature()。
\end{seeAlso}

int QMetaObject::indexOfProperty(const char \emph{*name}) const

查找名为 name 的属性并返回其编号，未找到则返回-1。

\begin{seeAlso}
property()、propertyCount() 和 propertyOffset()。	
\end{seeAlso}

int QMetaObject::indexOfSignal(const char \emph{*signal}) const

查找名为 name 的信号并返回其编号，未找到则返回-1。

此方法与 indexOfMethod() 相似，区别是若该方法存在但并非信号函数，则会返回 -1。

\begin{notice}
signal 需要为规范化的格式，如 normalizedSignature() 的返回值。	
\end{notice}

\begin{seeAlso}
indexOfMethod()、normalizedSignature(), method()、methodCount() 和 methodOffset()。
\end{seeAlso}

int QMetaObject::indexOfSlot(const char \emph{*slot}) const

查找名为 name 的槽并返回其编号，未找到则返回-1。

此方法与 indexOfMethod() 相似，区别是若该方法存在但并非槽函数，则会返回 -1。

\begin{seeAlso}
indexOfMethod()、method()、methodCount() 和 methodOffset()。
\end{seeAlso}

bool QMetaObject::inherits(const QMetaObject \emph{*metaObject}) const

若该 QMetaObject 继承自 \emph{metaObject} 描述的类型，则返回 true，否则返回 false。

一个类型被认为是继承自它自己的。

该函数在 Qt 5.7 中被引入。

%%%%%%
[static] bool QMetaObject::invokeMethod(QObject *obj, const char *member, 
 Qt::ConnectionType type, QGenericReturnArgument ret, 
 QGenericArgument val0 = QGenericArgument(nullptr), QGenericArgument val1 = QGenericArgument(), 
 QGenericArgument val2 = QGenericArgument(),QGenericArgument val3 = QGenericArgument(), 
 QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), 
 QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), 
 QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument())

通过 obj 对象动态调用它的 member 方法（或者信号和槽），若调用成功则返回 true，若该对象没有此方法或参数不匹配则返回 false。

该调用可以是同步或异步的，由 type 决定：

\begin{compactitem}
\item 若 type 是 Qt::DirectConnection，则该方法会被立即执行。
\item 若 type 是 Qt::QueuedConnection，则会发送一个 QEvent ，该方法会在应用进入该对象所属线程的主事件循环后执行。
\item 若 type 是 Qt::BlockingQueuedConnection，则该方法会通过与 Qt::QueuedConnection 相同的方式执行，
	此外当前线程会被阻塞，直到该事件被响应。使用此方法在相同线程的对象间通信会导致死锁。
\item 若 type 是 Qt::AutoConnection，当 obj 与调用者处于相同线程中时，该方法会被同步执行，否则会被异步执行。
\end{compactitem}

member 函数的返回值会被存放在 ret 中。若调用方式是异步，则返回值无法被获取。最多可以传递十个参数 (val0, val1, val2, val3, val4, val5, val6, val7, val8 和 val9) 至 member 函数。

QGenericArgument 和 QGenericReturnArgument 是内部的辅助类。为了动态调用信号槽，您需要将参数通过 Q\_ARG() 和 Q\_RETURN\_ARG() 宏进行封装。
Q\_ARG() 接受一个类型名称和一个该类型的不可变引用；
Q\_RETURN\_ARG() 接受一个类型名称和一个该类型的可变引用。

您只需要将信号槽的名称传递至本函数，无需传递完整的签名。

例如，异步调用某个 QThread 对象的 quit() 槽需要的代码如下：

\begin{cppcode}
QMetaObject::invokeMethod(thread, "quit",
                           Qt::QueuedConnection);
\end{cppcode}

当异步调用方法时，传递的参数必须被 Qt 的元对象系统所知悉，因为 Qt 需要在后台事件中拷贝并保存它们。
如果您使用队列连接时遇到下述错误信息：

\begin{lstlisting}
QMetaObject::invokeMethod: Unable to handle unregistered datatype 'MyType'
\end{lstlisting}

则在调用 invokeMethod() 之前通过 qRegisterMetaType() 来注册该数据类型。

若想通过 obj 对象同步调用 compute(QString, int, double) 槽，则代码如下：

\begin{cppcode}
 QString retVal;
 QMetaObject::invokeMethod(obj, "compute", Qt::DirectConnection,
                           Q_RETURN_ARG(QString, retVal),
                           Q_ARG(QString, "sqrt"),
                           Q_ARG(int, 42),
                           Q_ARG(double, 9.7));
\end{cppcode}

若 compute 槽通过特定顺序没有完整获取到一个 QString、一个 int 和一个 double，则此调用会失败。

\begin{notice}
此方法是线程安全的。
\end{notice}

\begin{seeAlso}
Q\_ARG()、Q\_RETURN\_ARG()、qRegisterMetaType() 和 QMetaMethod::invoke()。
\end{seeAlso}

%%%%%%%%%%%

[static] bool QMetaObject::invokeMethod(QObject \emph{*obj}, const char \emph{*member}, QGenericReturnArgument \emph{ret}, 
QGenericArgument val0 = QGenericArgument(0), QGenericArgument val1 = QGenericArgument(), 
QGenericArgument val2 = QGenericArgument(), 
QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), 
QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), 
QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), 
QGenericArgument val9 = QGenericArgument())

此函数是 invokeMethod() 的重载。

此重载始终通过 Qt::AutoConnection 调用对应方法。

\begin{notice}
此方法是线程安全的。
\end{notice}

[static] bool QMetaObject::invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericArgument val0 = QGenericArgument(0), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument())

此函数是 invokeMethod() 的重载。

此重载用于不关心对返回值的场合。


\begin{notice}
此方法是线程安全的。
\end{notice}


[static] bool QMetaObject::invokeMethod(QObject \emph{*obj}, const char \emph{*member}, 
 QGenericArgument val0 = QGenericArgument(0), QGenericArgument val1 = QGenericArgument(),
  QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(),
   QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), 
   QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), 
   QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument())

此函数是 invokeMethod() 的重载。

此重载通过 Qt::AutoConnection 调用对应方法，并忽略返回值。

\begin{notice}
此方法是线程安全的。
\end{notice}

[static] template <typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject \emph{*context}, Functor \emph{function}, Qt::ConnectionType \emph{type} = Qt::AutoConnection, FunctorReturnType \emph{*ret} = nullptr)

此函数是 invokeMethod() 的重载。

通过 type 方式在 \emph{context} 所属的事件循环中动态调用 \emph{function}。\emph{function} 可以是一个仿函数或成员函数指针。
若该函数可被动态调用则返回 true，当该函数不存在或参数不匹配时返回 false。函数的返回值将被保存至 \emph{ret} 中。

\begin{notice}
此方法是线程安全的。
\end{notice}

该函数在 Qt 5.10 中被引入。

[static] template <typename Functor, typename FunctorReturnType> bool QMetaObject::invokeMethod(QObject \emph{*context}, Functor \emph{function}, FunctorReturnType \emph{*ret})

此函数是 invokeMethod() 的重载。

通过 Qt::AutoConnection 方式动态调用 \emph{function}。\emph{function} 可以是一个仿函数或成员函数指针。
若该函数可被动态调用则返回 true，当该函数不存在或参数不匹配时返回 false。函数的返回值将被保存至 \emph{ret} 中。


\begin{notice}
此方法是线程安全的。
\end{notice}


该函数在 Qt 5.10 中被引入。

QMetaMethod QMetaObject::method(int \emph{index}) const

返回指定 \emph{index} 的方法的元数据。

\begin{seeAlso}
methodCount(), methodOffset() 和 indexOfMethod().
\end{seeAlso}

int QMetaObject::methodCount() const

返回该类中方法的数量，包括所有基类的方法个数。除了常规成员函数外，也包含信号函数和槽函数。

使用下述代码来将所给类的所有方法签名存储至 QStringList：

\begin{cppcode}
 const QMetaObject* metaObject = obj->metaObject();
 QStringList methods;
 for(int i = metaObject->methodOffset(); i < metaObject->methodCount(); ++i)
     methods << QString::fromLatin1(metaObject->method(i).methodSignature());
\end{cppcode}

\begin{seeAlso}
method()、methodOffset() 和 indexOfMethod()。
\end{seeAlso}

int QMetaObject::methodOffset() const

返回类方法在该类中的偏移量，即第一个类方法的编号。

该偏移量是所有父类的方法数总和（因此总为正数，因为 QObject 有 deleteLater() 槽和 destroyed() 信号）。

\begin{seeAlso}
method()、methodCount() 和 indexOfMethod()。
\end{seeAlso}

QObject *QMetaObject::newInstance(QGenericArgument \emph{val0} = QGenericArgument(nullptr), QGenericArgument \emph{val1} = QGenericArgument(), 
    QGenericArgument \emph{val2} = QGenericArgument(), QGenericArgument \emph{val3} = QGenericArgument(), 
    QGenericArgument \emph{val4} = QGenericArgument(), QGenericArgument \emph{val5} = QGenericArgument(), 
    QGenericArgument \emph{val6} = QGenericArgument(), QGenericArgument \emph{val7} = QGenericArgument(), 
    QGenericArgument \emph{val8} = QGenericArgument(), QGenericArgument \emph{val9} = QGenericArgument()) const

构造一个此类的新实例。您可以传递最多十个参数 (val0, val1, val2, val3, val4, val5, val6, val7, val8 和 val9) 至构造函数。返回构造的新对象，若没有合适的构造函数则返回 nullptr。

\begin{notice}
只有通过 Q\_INVOKABLE 修饰符声明的构造函数才能在元对象系统中使用。
\end{notice}

该函数在 Qt 4.5 中被引入。

\begin{seeAlso}
Q\_ARG() 和 constructor()。
\end{seeAlso}

[static] QByteArray QMetaObject::normalizedSignature(const char \emph{*method})

将给予的 \emph{method} 进行规范化。

Qt 使用规范化的签名来来判断两个给定的信号和槽是否匹配。
规范化操作会将空格减到最少，将 const 适当前移，移除值类型的 const，并将不可变引用替换为值类型。

\begin{seeAlso}
checkConnectArgs() 和 normalizedType()。
\end{seeAlso}

[static] QByteArray QMetaObject::normalizedType(const char \emph{*type})

将 \emph{type} 规范化。

请参阅 QMetaObject::normalizedSignature() 中关于 Qt 如何进行规范化的描述。

范例:

\begin{cppcode}
 QByteArray normType = QMetaObject::normalizedType(" int    const  *");
 // 规范化的类型将为 "const int*"
\end{cppcode}

%%%%%%%%%%%%%%%%%%

该函数在 Qt 4.2 中被引入。

\begin{seeAlso}
normalizedSignature()。
\end{seeAlso}

QMetaProperty QMetaObject::property(int \emph{index}) const

返回指定 \emph{index} 的属性的元数据。
若该属性不存在，则返回空的 QMetaProperty 对象。

\begin{seeAlso}
propertyCount()、propertyOffset() 和 indexOfProperty()。
\end{seeAlso}

int QMetaObject::propertyCount() const

返回该类中属性的类型，包括所有基类的属性个数。

使用如下代码来将给定类的所有属性名称保存至 QStringList: 

\begin{cppcode}
 const QMetaObject* metaObject = obj->metaObject();
 QStringList properties;
 for(int i = metaObject->propertyOffset(); i < metaObject->propertyCount(); ++i)
     properties << QString::fromLatin1(metaObject->property(i).name());
\end{cppcode}

\begin{seeAlso}
property()、propertyOffset() 和 indexOfProperty()。
\end{seeAlso}

int QMetaObject::propertyOffset() const

返回类属性在该类中的偏移量，即第一条类属性的编号。

该偏移量包含所有父类的类属性数量总和（因此总为正数，因为 QObject 有 name() 属性）。

\begin{seeAlso}
property()、propertyCount() 和 indexOfProperty()。
\end{seeAlso}

const QMetaObject *QMetaObject::superClass() const

返回父类的元对象，若不存在则返回 \hl{nullptr}。

\begin{seeAlso}
className()。
\end{seeAlso}

QMetaProperty QMetaObject::userProperty() const

返回 \hl{USER} 标志位为 \hl{true} 的元属性。

该函数在 Qt 4.2 中被引入。

\begin{seeAlso}
QMetaProperty::isUser()。
\end{seeAlso}

\section{宏定义文档}

QGenericArgument Q\_ARG(Type, const Type \emph{\&value})

该宏接受一个 \hl{type} 和一个该类型的 \hl{value} 参数，

返回一个用于传递至 QMetaObject::invokeMethod() 的 QGenericArgument 对象。

\begin{seeAlso}
Q\_RETURN\_ARG()。
\end{seeAlso} 

QGenericReturnArgument Q\_RETURN\_ARG(\emph{Type}, Type \emph{\&value})

该宏接受一个 \hl{Type} 和一个该类型的可变引用 \hl{value} 参数，

返回一个用于传递至 QMetaObject::invokeMethod() 的包含该类型的 QGenericReturnArgument 对象。

\begin{seeAlso}
Q\_ARG()。
\end{seeAlso} 